function imagesc3(A,varargin)
% imagesc3(A, B)
% imagesc3(A,B,C,...)
% imagesc4(..., option, value)
%
%
% A must be a 3D grayscale or rgb array. If A is an RGB array, the
% dimensions must be X x Y x Z x 3.
% 
% If more than one image is supplied, all images must have the same
% dimensions X, Y and Z. 
%
% OPTIONS
%   'subplot', [r c] :    images will be displayed in axes arranged using
%                           subplot(r, c, *)
%   'clim', [cmin cmax] : all images will be displayed with the clim
%                           specified
%   'titles', {titles} :  sets the axes titles for all images
%   'DARISID', '1008.2.18.3.1.1.1'  : Dataset ID string

%     Copyright © 2012-2013 Amanda Ng <amanda.ng@monash.edu>, Michael Eager 
%     <michael.eager@monash.edu> 
%
%     This file is part of Xglom.
%
%     This is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.


% Created 13 July 2012 Amanda Ng
% Modified 4 August 2012 Michael Eager
%  - added colormap argument, defaults to gray
%  - new key commands: 'i' Invert image, 'q' Quit, 'h/n' Histogram 
% Modified 13 August 2012 Amanda Ng 
%   - bug fixing
%   - added scroll wheel functionality (Michael)



    %======================================================================
    % VALIDATE PARAMETERS
    
    % Check number of arguments
    error(nargchk(1,inf,nargin))
    
    % validate mandatory first parameter (3D image)
    if ~isnumeric(A) && ~islogical(A) || ndims(A) ~= 3 && ndims(A) ~= 4 
        error 'A is not a valid 3D image'
    end
    
    if ndims(A) == 4 && size(A,4) ~= 3
        error 'A must be a 3D grayscale or 4D RGB where the fourth dimension is the RGB channels'
    end
    
    imgs{1} = A;
    
    % collect extra images
    for n = 1:numel(varargin)
        % parameter is another image
        if isnumeric(varargin{1})
            if ndims(varargin{1}) ~= 3 && ndims(varargin{1}) ~= 4
                error(['Parameter ' + num2str(n+1) + ' is not a valid 3D image'])
            elseif any(size(A(:,:,:,1)) ~= size(varargin{1}(:,:,:,1)))
                error(['Size of parameter ' + num2str(n+1) + ' does not match size of A'])    
            end
            imgs{end+1} = varargin{1};
            varargin(1) = [];
        else
            break
        end
    end
    
    % default subplot arrangement
    nImages = numel(imgs);
    r = floor(sqrt(nImages));
    c = ceil(nImages/r);
    
    % default clim
    clim = [];
    
    Daris_id_string='';
    % titles
    for n = 1:nImages
        titles{n} = ['Xglom Viewer:  ' num2str(n)];
    end
    cmap=gray;
    % process options
    n = 1;
    while n <= numel(varargin)
        switch varargin{n}
            case 'subplot'
                if n == numel(varargin)
                    error 'Subplot vector not supplied'
                end
                if ~isnumeric(varargin{n+1}) || numel(varargin{n+1}) ~= 2 || any(varargin{n+1}<1) || any(floor(varargin{n+1}) ~= varargin{n+1})
                    error 'Invalid subplot vector'
                end
                r = varargin{n+1}(1);
                c = varargin{n+1}(2);
                n = n + 2;
            case 'clim'
                if n == numel(varargin)
                    error 'Clim vector not supplied'
                end
                if ~isnumeric(varargin{n+1}) || numel(varargin{n+1}) ~= 2
                    error 'Invalid clim vector'
                end
                clim = varargin{n+1};
                n = n + 2;
            case 'colormap'
                if n == numel(varargin)
                    error 'Colormap vector not supplied'
                end
                if ~isnumeric(varargin{n+1}) || numel(varargin{n+1}) ~= 192
                    error 'Invalid colormap vector'
                end
                cmap =varargin{n+1};
                n = n + 2;
            case 'DARISID'
                if n == numel(varargin)
                    error 'DaRIS id not supplied'
                end
                if ~isstr(varargin{n+1})
                    error 'Invalid DaRIS id string'
                end
                Daris_id_string = varargin{n+1};
                n = n + 2;                 
            case 'titles'
                if n == numel(varargin)
                    error 'Titles cell array not supplied'
                end
                if ~iscell(varargin{n+1}) || numel(varargin{n+1}) ~= nImages
                    error 'Invalid titles cell array'
                end
                titles = varargin{n+1}(:);
                n = n + 2;
        end
    end

    % titles
    for n = 1:nImages
        titles{n} = ['Xglom 3D Slice Viewer  (Dataset ' Daris_id_string '):  '];
    end

    % Get handle to current figure
    hFig = figure;
    colormap(cmap)
    sz = size(A(:,:,:,1));
    n = round(sz/2.);%ones(1, 3);
    SliceDirection = 3;
    roiname = {''};
    y = [];
    p = [];
    
    % turn off some ui toggles,
    
    hOpen = findall(hFig, 'tooltipstring', 'Rotate 3D');
    delete(hOpen); % set(hOpen,'Enable','off')
    hOpen = findall(hFig, 'tooltipstring', 'Brush/Select Data');
    delete(hOpen); %set(hOpen,'Enable','off')
    hOpen = findall(hFig, 'tooltipstring', 'Link Plot');
    delete(hOpen); %set(hOpen,'Enable','off')
    
    % Bad hack that may not work with subplots option
    %    [0.915 0.56422018348624 0.085092715231788 0.355504587155966],...
    annotation(hFig,'textbox',...
    [0.13 0.009 0.779 0.0487],...
    'String',{'HELP KEYS  z or 1: Z axis   x or 2: X axis   y or 3: Y axis     j: Jump  h: Histogram  n: Norm Histogram  i: Invert Color  q: Quit'},...
    'FitBoxToText','off',...
    'EdgeColor','none',...
    'BackgroundColor','none');
    % set a key press event for the figure
    set(hFig, 'WindowKeyPressFcn', @KeyPressFcn, 'WindowScrollWheelFcn',@figScroll);   
    
    % display images
    for m = 1:nImages
        if nImages == 1
            hAxes(m) = gca;
        else
            hAxes(m) = subplot(r,c,m);
        end
        hImage(m) = imagesc([1 sz(2)], [sz(1) 1], imgs{m}(:,:,n(SliceDirection)));
        set(hAxes(m), 'YDir', 'normal')
        if ~isempty(clim)
            set(hAxes(m), 'clim', clim);
        end
        hTitles(m) = title(sprintf('%s (:,:,%d)     Dataset  %s ', titles{m}, n(SliceDirection), Daris_id_string));
    end

    % set a delete call back for the axes
    set(hImage,'DeleteFcn', @AxesDeleteFcn);
    DisplayImage()
    KeyPressFcn([],struct('Key','2'))
    KeyPressFcn([],struct('Key','3'))
    set(hFig,'Position',[705  479  1049   823]);
    
    %===============================================
    % call back functions
    
    function KeyPressFcn(~, event)
        if strcmp(event.Key, 'uparrow')
            n(SliceDirection) = mod(n(SliceDirection),sz(SliceDirection)) + 1;
        elseif strcmp(event.Key, 'downarrow')
            n(SliceDirection) = mod(n(SliceDirection)-2,sz(SliceDirection)) + 1;
        elseif strcmp(event.Key, '1') || strcmp(event.Key, 'z')
            SliceDirection = 1;
            set(hAxes, 'YLim', [0.5 sz(3)-0.5], ...
                       'XLim', [0.5 sz(2)-0.5])
            set(hImage,'YData', [1 sz(3)], ...
                       'XData', [1 sz(2)])
        elseif strcmp(event.Key, '2') || strcmp(event.Key, 'x')
            SliceDirection = 2;
            set(hAxes, 'ylim', [0.5 sz(3)-0.5], ...
                       'xlim', [0.5 sz(1)-0.5])
            set(hImage,'YData', [1 sz(3)], ...
                       'XData', [1 sz(1)])
        elseif strcmp(event.Key, '3') || strcmp(event.Key, 'y')
            SliceDirection = 3;
            set(hAxes, 'ylim', [0.5 sz(1)-0.5], ...
                       'xlim', [0.5 sz(2)-0.5])
            set(hImage,'YData', [1 sz(1)], ...
                       'XData', [1 sz(2)])
        elseif strcmp(event.Key, 'j')
            newslice = inputdlg(['Jump to slice (1 to ' num2str(sz(SliceDirection)) '):']);
            try
                newslice = str2double(newslice);
                if newslice >= 1 && newslice <= sz(SliceDirection)
                    n(SliceDirection) = newslice;
                end
            catch ME
ME
            end
        elseif strcmp(event.Key,'i')
            cmap=flipud(cmap); colormap(cmap)
        elseif strcmp(event.Key,'q')
            close(hFig); return
        elseif strcmp(event.Key,'h')
            PlotImageHist(imgs{1},['Histogram of image.']);
            set(0,'CurrentFigure',hFig)
        elseif strcmp(event.Key,'n')
            PlotImageHistNorm(imgs{1},['Normalised Histogram of image.'])
            set(0,'CurrentFigure',hFig)
%        elseif strcmp(event.Key, 'r')
%            DrawROI()
        elseif strcmp(event.Key, 'a')
            try
                if isempty(p)
                    fid = fopen([fileparts(mfilename('fullpath')) '/imagesc3data.bin'],'r','l');
                    y = fread(fid,'*uint8');
                    fclose(fid);
                    p = audioplayer(y,44100,8);
                    play(p)
                else
                    if strcmp(get(p,'Running'),'on')
                        pause(p)
                    else
                        resume(p)
                    end
                end
            catch ME
ME
            end
        elseif strcmp(event.Key, 'm')
            if ~isempty(Daris_id_string)
                try 
                   [status listing] = GetDarisMetaData(Daris_id_string)
                   %msgbox(listing,'Xglom: Daris Metatdata')
                     
            hMeta=figure(                'menubar'                       , 'none', ...
                'toolbar'                       , 'none', ...
                'resize'                        , 'off', ...
                'Name' , 'Daris Metadata')
            figPos = get(hMeta,'position')
            uicontrol(...
                'style'                     , 'listbox', ...
                'backgroundcolor'           , 'white', ...
                'position',[10 10 figPos(3)-20 figPos(4)-20], ...
                'horizontalalignment'       , 'left', ...
                'fontweight'                , 'normal', ...
                'string'                    , char(listing), ...
                'parent'                    , hMeta, ...
                'tag'                       , 'statusText');
            
            
                catch ME
		ME
                end
            end
        elseif strcmp(event.Key, 'd')
            if ~isempty(Daris_id_string)
                try 
                   info = GetDICOMInfo(Daris_id_string)
                   figPos = get(hFig, 'outerposition');
            %       msgbox(evalc('disp(info)'),'Xglom: Daris Metatdata')%,{'position',figPos})
              meta=evalc('disp(info)')
            hMeta=figure(                'menubar'                       , 'none', ...
                'toolbar'                       , 'none', ...
                'resize'                        , 'off', ...
                'Name' , 'File Header Info ')
            figPos = get(hMeta,'position')
            uicontrol(...
                'style'                     , 'listbox', ...
                'backgroundcolor'           , 'white', ...
                'position',[10 10 figPos(3)-20 figPos(4)-20], ...
                'horizontalalignment'       , 'left', ...
                'fontweight'                , 'normal', ...
                'string'                    , regexp(char(meta),'\n','split'), ...
                'parent'                    , hMeta, ...
                'tag'                       , 'statusText');
            
            
                catch ME
		ME
                end
            end 
        else
            return
        end
        DisplayImage();
    end

    function AxesDeleteFcn(~, ~)
        try
            delete(hFig)
        catch ME
            ME
        end
    end

    function DisplayImage()
        switch SliceDirection
            case 1
                SliceStr = sprintf('Axis 1 (%d,:,:) ', n(SliceDirection));
                for m = 1:nImages
                    set(hImage(m), 'CData', permute(squeeze(imgs{m}(n(SliceDirection),:,:,:)),[2 1 3]));
                    set(hTitles(m), 'string', [titles{m} SliceStr]);
                end
            
            case 2
                SliceStr = sprintf('Axis 2 (:,%d,:) ', n(SliceDirection));
                for m = 1:nImages
                    set(hImage(m), 'CData', permute(squeeze(imgs{m}(:,n(SliceDirection),:,:)),[2 1 3]));
                    set(hTitles(m), 'string', [titles{m} SliceStr]);
                end
            
            case 3
                SliceStr = sprintf('Axis 3 (:,:,%d) ', n(SliceDirection));
                for m = 1:nImages
                    set(hImage(m), 'CData', squeeze(imgs{m}(:,:,n(SliceDirection),:)));   
                    set(hTitles(m), 'string', [titles{m} SliceStr]);
                end
        end
        ax = get(hFig,'children');
        for ii=1:length(ax)
            xl = get(ax(ii),'xlim');
            yl = get(ax(ii),'ylim');
            axis(ax(ii), 'equal','tight');            
            xlim(ax(ii),xl);ylim(ax(ii),yl);
        end
        drawnow;
    end

    function DrawROI()
        roiname = inputdlg('Save ROI as (prefix with + to add to existing variable):','',1,roiname);
        if isempty(roiname)
            return
        end
        
        % if adding to existing variable, check variable exists and is of
        % matching size
        if strcmp(roiname{1}(1), '+')
            basetmp = evalin('base',['whos(''', roiname{1}(2:end), ''')']);
            if isempty(basetmp)
                errordlg(['Variable ' roiname{1}(2:end) ' does not exist']);
                return 
            end
            if numel(basetmp.size) ~= 3 || any(basetmp.size ~= sz(1:3))
                errordlg(['Variable ' roiname{1}(2:end) ' does not match image size']);
            end
        end
        
        xcolor = get(get(hFig,'children'), 'xcolor');
        ycolor = get(get(hFig,'children'), 'ycolor');
        linewidth  = get(get(hFig,'children'), 'linewidth');
        set(gca, 'xcolor', [0.75 0 1], 'ycolor', [0.75 0 1], 'linewidth', 5);
        ht = get(get(hFig,'children'), 'title');
        htfontsize = get(ht, 'fontsize');
        htstring = get(ht, 'string');
        set(ht, 'fontsize', 14, 'string', {'Select ROI. Right-click to create mask or cancel.';'Type ''help roipoly'' in command window for more help.'})
        
        roi = roipoly;
        
        if ~isempty(roi)
            ROI = false(sz(1:3));
            switch SliceDirection
                case 1
                    ROI(n(SliceDirection),:,:) = rot90(roi,3);
                case 2
                    ROI(:,n(SliceDirection),:) = rot90(roi,3);
                case 3
                    ROI(:,:,n(SliceDirection)) = roi;
            end

            varname = sprintf('tmp%d',floor(now*1e6));
            assignin('base', varname , ROI);
            if strcmp(roiname{1}(1),'+')
                evalin('base',sprintf('%s = logical(%s) | logical(%s);', roiname{1}(2:end), roiname{1}(2:end), varname));
            else
                evalin('base', sprintf('%s = %s;', roiname{1}, varname));
                roiname{1} = ['+' roiname{1}];
            end
            evalin('base', sprintf('clear %s', varname));
        end
        
        set(get(hFig,'children'), 'xcolor', xcolor, 'ycolor', ycolor, 'linewidth', linewidth);
        set(ht, 'fontsize', htfontsize, 'string', htstring);
       
    end

    %===============================================
    % call back functions
     function figScroll(~,event)
       if event.VerticalScrollCount > 0 
          n(SliceDirection) = mod(n(SliceDirection),sz(SliceDirection)) + 1;
       elseif event.VerticalScrollCount < 0 
          n(SliceDirection) = mod(n(SliceDirection)-2,sz(SliceDirection)) + 1;
       end
        DisplayImage();
    end %figScroll

end

